﻿using System.Linq;
using Notoric.Commanding.CommandBase;
using LukasKopenec.LocalizationSupport;

namespace Notoric.ViewModel
{
    /// <summary>
    /// Implements an undoable command for creating a new directory.
    /// </summary>
    /// <remarks>
    /// Input Parameters<br/>
    /// <list type="table">
    /// <listheader>
    /// <term>
    ///     Name (Type)
    /// </term>
    /// <description>
    ///     Description
    /// </description>
    /// </listheader>
    /// <item>
    /// <term>
    ///     Parent (<see cref="Directory"/>)
    /// </term>
    /// <description>
    ///     The directory in which the new one will be created.
    /// </description>
    /// </item>
    /// <item>
    /// <term>
    ///     DirectoryName (<see cref="string"/>
    /// </term>
    /// <description>
    ///     The name of the new directory.
    /// </description>
    /// </item>
    /// </list>
    /// <br/>
    /// Output Parameters:<br/>
    /// <list type="table">
    /// <listheader>
    /// <term>
    ///     Name (Type)
    /// </term>
    /// <description>
    ///     Description
    /// </description>
    /// </listheader>
    /// <item>
    /// <term>
    ///     CreatedDirectory (<see cref="Directory"/>)
    /// </term>
    /// <description>
    ///     The created directory.
    /// </description>
    /// </item>
    /// </list>
    /// <br/>
    /// The command can execute if all the input parameters are set to non-null values and the <see cref="Parent"/> does not contain
    /// another child with the same name.
    /// </remarks>
    public class NewDirectoryCommand : UndoableCommandBase
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="NewDirectoryCommand"/> instance.
        /// </summary>
        /// <param name="undoStack">
        /// <para>
        /// Type: <see cref="CommandStack"/>
        /// </para>
        /// <para>
        /// The command stack where the command will be put after its execution.
        /// </para>
        /// </param>
        /// <param name="redoStack">
        /// <para>
        /// Type: <see cref="CommandStack"/>
        /// </para>
        /// <para>
        /// The command stack where the command will be put when it has been undone.
        /// </para>
        /// </param>
        public NewDirectoryCommand(CommandStack undoStack, CommandStack redoStack)
            : base(undoStack, redoStack)
        {
            AddParameter<Directory>("Parent", ParameterDirection.In);
            AddParameter<string>("DirectoryName", ParameterDirection.In);
            AddParameter<Directory>("CreatedDirectory", ParameterDirection.Out);

            Name = (string)LocalizationManager.GetValue("Commands.Names.NewDirectory");
        }

        #endregion

        #region Command Logic

        /// <inheritdoc/>
        public override bool CanExecute(object parameter)
        {
            return base.CanExecute(parameter) && Parent != null && !Parent.Children.Any(item => item.DisplayName == DirectoryName);
        }

        /// <inheritdoc/>
        protected override void CommandOperation(object parameter)
        {
            CreatedDirectory = new Directory(Parent, DirectoryName, Parent.ContextMenu);
            Parent.Children.Add(CreatedDirectory);

            CreatedDirectory.IsSelected = true;
        }

        /// <inheritdoc/>
        protected override void RedoOperation()
        {
            Parent.Children.Add(CreatedDirectory);
        }

        /// <inheritdoc/>
        protected override void UndoOperation()
        {
            Parent.Children.Remove(CreatedDirectory);
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the created directory.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Directory"/>
        /// </para>
        /// <para>
        /// The created directory.<br/>
        /// This property wraps the "CreatedDirectory" command parameter.
        /// </para>
        /// </value>
        public Directory CreatedDirectory
        {
            get { return GetParameterValue<Directory>("CreatedDirectory"); }
            private set { SetParameterValue<Directory>("CreatedDirectory", value); }
        }

        /// <summary>
        /// Gets or sets the name of the new directory.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// The name of the new directory.<br/>
        /// This property wraps the "DirectoryName" command parameter.
        /// </para>
        /// </value>
        public string DirectoryName
        {
            get { return GetParameterValue<string>("DirectoryName"); }
            set { SetParameterValue<string>("DirectoryName", value); }
        }

        /// <summary>
        /// Gets or sets the <see cref="Directory"/> in which the new one will be created.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Directory"/>
        /// </para>
        /// <para>
        /// The directory in which the new directory will be created.<br/>
        /// This property wraps the "Parent" command parameter.
        /// </para>
        /// </value>
        public Directory Parent
        {
            get { return GetParameterValue<Directory>("Parent"); }
            set { SetParameterValue<Directory>("Parent", value); }
        }

        #endregion
    }
}
